home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
QRZ! Ham Radio 6
/
QRZ Ham Radio Callsign Database - Volume 6.iso
/
mac
/
files
/
pbbs
/
iosc51.arc
/
BR1BIOS.ASM
next >
Wrap
Assembly Source File
|
1988-02-15
|
19KB
|
657 lines
PAGE 60,132
TITLE BR1BIOS - Serial interface for COM1
;Interupt driven RS232 serial port routines.
; these routines replace the BIOS rs232 calls with a version that has
; interupt driven character receive, and can thus operate at considerably
; higher speeds than the standard bios calls (int 14h).
; Added break function (7).
; Set up the works
everything SEGMENT PUBLIC
ASSUME CS: everything ; These assumptions are for the
ASSUME DS: everything ; assembler's benefit. The code
ASSUME ES: nothing ; jerks things around as it pleases
ASSUME SS: nothing
; Program start and buffer declares
ORG 100H
foo: jmp start ; Entry point
org 0 ; Back up so we can use this all as
; buffer space
; Area where things are declared
include constbios.asm
dummy: ; Dummy labels to provide a structure
i_buf db buffer_size dup(?) ; Buffer (1 per com card)
i_buf_e: ; End of buffer
comnumber db ? ; Comm number - 1
flags db ? ; Flag byte
last_rs db ? ; Last receive status
hiv db ? ; Hardware interrupt vector
int_mask db ? ; Mask for 8259
baseaddr dw ? ; Base port address
i_count dw ? ; # of chars in buffer
i_buf_in dw ? ; Buffer in pointer
i_buf_out dw ? ; Buffer out pointer
dummy_end:
org dummy ; Back up over this
; These are the things to work with
db buffer_size dup(?) ; Buffer (1 per com card)
db 0 ; Com number
db 0 ; Flags
db 0 ; Last receive status
db 0ch ; Hardware interrupt vector
db 0efh ; Mask
dw 03f8h ; Base port address
dw 0 ; # of chars in buffer
dw ? ; Buffer in pointer
dw ? ; Buffer out pointer
comend: ; Marker for last com port
; Static variables
old_bios_vector dw ? ; Save previous interrupt vector
dw ?
divisor_table LABEL WORD
dw 1047 ; 110
dw 768 ; 150
dw 384 ; 300
dw 192 ; 600
dw 96 ; 1200
dw 48 ; 2400
dw 24 ; 4800
dw 12 ; 9600
; Our BIOS handler
rsint:
ASSUME DS: NOTHING ; Don't use DS
ASSUME ES: NOTHING ; Don't use ES
ASSUME SS: NOTHING ; Don't use SS
; Not disabled please
sti
; See if this is our vector?
push bp ; Save BP over our loop
xor bp,bp
cmp dl,cs:comnumber[bp] ; Is this our port?
je rsint_ours ; Yes...
; Not us.. Pop things out and call regular handler
pop bp
jmp cs:dword ptr old_bios_vector
; BP now contains the pointer to the com block... See what
; the user has requested and we may or may not do it.......
rsint_ours:
push dx ; We need the DX register
push cx ; We need the CX register
push bx ; We need the BX register
mov cx,baseaddr[bp] ; Get base address for chip
or ah,ah ; Initialize?
je rsint_init ; Yes...
dec ah ; 1 = Send character
jz rsint_send
dec ah ; 2 = Receive character
jz rsint_recv_jmp
dec ah ; 3 = Status request
jz rsint_status_jmp
dec ah ; 4 = Inquiry
jz rsint_inquiry_jmp
dec ah
dec ah
dec ah
jz rsint_break_jmp ; 7 = send break
jmp rsint_exit ; Nope..
rsint_recv_jmp:
jmp rsint_recv
rsint_status_jmp:
jmp rsint_status
rsint_inquiry_jmp:
jmp rsint_inquiry
rsint_break_jmp:
jmp rsint_break
; Interrupt exit
rsint_exit:
pop bx ; Restore registers
pop cx
pop dx
pop bp
iret ; and leave
; Init..
rsint_init:
mov ah,al ; Save the parms for later
mov bl,ah ; Look up the baud rate
mov cl,4 ; parameter
rol bl,cl
and bx,0eh
mov bx,divisor_table[bx]
mov cx,baseaddr[bp] ; Get base address for chip
mov dx,cx ; Address of LCR
add dx,lcr_8250
mov al,10000000B ; Enable access to divisor
out dx,al
mov dx,cx ; Address of lower divisior half
add dx,dll_8250
mov al,bl ; Put lower half
out dx,al
mov dx,cx ; Address of upper divisior half
add dx,dlm_8250
mov al,bh ; Put upper half
out dx,al
mov al,ah ; Get parms back
and al,1fh ; Throw away baud rate
mov dx,cx ; Address of LCR
add dx,lcr_8250
out dx,al ; Output the parms
; Turn on the port
mov dx,cx ; Compute port address for the MCR
add dx,mcr_8250
mov al,00001011B ; Raise DTR, RTS & OUT2
out dx,al ; OUT2 turns on interrupts
jmp rsint_status ; Now just status please
; Send a character
rsint_send:
mov ah,al ; Save the character to send
rsint_send_loop: ; Loop here until we can send
mov dx,cx ; Compute port address for the MSR
add dx,msr_8250 ; and then
in al,dx ; get it into AX
and al,10h ; CTS
jz rsint_send_loop
mov dx,cx ; Compute port address for the LSR
add dx,lsr_8250 ; and then
in al,dx ; get itinto AX
and al,20h ; THR empty?
jz rsint_send_loop ; No.. Loop back
mov al,ah ; Get ready to out character
mov dx,cx ; Compute port address for the THR
; add dx,thr_8250 ; and then
out dx,al ; out the character
jmp rsint_status ; Do a status
; Receive a character
rsint_recv:
MOV BX,i_buf_out[BP] ; Get buffer output pointer
rsint_recv_loop:
CMP i_count[BP],0 ; Anything in buffer?
JE rsint_recv_loop ; No, Wait for it
rsint_get_char:
MOV AL,CS:[BX] ; Get character from buffer
PUSH AX ; Save char
INC BX ; Bump pointer
DEC i_count[BP] ; Dec char count
MOV DX,OFFSET i_buf_e ; Compute end of buffer
ADD DX,BP
CMP BX,DX ; Have we wrapped the buffer?
JL test_handshake ; No.. All done
MOV BX,OFFSET i_buf ; Yes.. Reset pointer
ADD BX,BP
test_handshake:
cmp i_count[BP],80H
jnb test_full
mov ah,flags[BP]
test ah,1 ; Did we RTS off?
jz test_full ; No, so don't RTS on
roll_hands:
mov DX,CX
add DX,mcr_8250
in AL,DX
or AL,00001011B ; Raise DTR, RTS & OUT2
out DX,AL
and AH,0FEH ; Remember RTS is on
mov flags[BP],AH
test_full:
POP AX ; Restore Char
MOV i_buf_out[BP],BX ; Save pointer
MOV AH,last_rs[BP] ; Get last LSR from receive
AND AH,0FEH ; Remove data ready bit
CMP i_count[BP],0 ; Anything left in buffer?
JE short_exit ; Nope so leave
OR AH,1 ; Turn on data ready
short_exit:
JMP rsint_exit ; and go leave
; Status..
rsint_status:
MOV DX,CX ; Compute port address for the LSR
ADD DX,lsr_8250 ; and then
IN AL,DX ; get it
AND AL,0FEH ; Remove data ready bit
CMP i_count[BP],0 ; Anything left in buffer?
JE rsint_status_nodr ; Nope so leave
OR AL,1 ; Turn on data ready
rsint_status_nodr:
MOV AH,AL ; Save LSR
MOV DX,CX ; Compute port address for the MSR
ADD DX,msr_8250 ; and then
IN AL,DX ; get it
JMP rsint_exit ; All done
; Inquiry
; (Return AA55H in AX - Just an identification scheme to tell
; if this silly driver has been loaded)
rsint_inquiry:
MOV AX,0AA55H
JMP rsint_exit ; and go leave
; send break
rsint_break:
mov dx,cx
add dx,lcr_8250
in al,dx
mov bl,al
mov al,40h
out dx,al
mov cx,0
bkwait: loop bkwait
mov al,bl
out dx,al
jmp rsint_exit
; 8250 interrupt handler
serint_8250:
PUSH BP
PUSH DX
PUSH AX
PUSH CX ; Save some registers
PUSH DI
xor bp,bp
MOV CX,baseaddr[BP] ; Get base address for chip
MOV DX,CX ; Get the IIR
ADD DX,iir_8250
IN AL,DX
TEST AL,1 ; Interrupt pending?
JZ service
JMP serint_8250_exit ; No leave...
service:
MOV DX,CX ; Get the LSR
ADD DX,lsr_8250
IN AL,DX
MOV last_rs[BP],AL ; And tuck it away
MOV DX,CX ; Get the RBR
; ADD DX,rbr_8250
IN AL,DX
MOV DI,i_buf_in[BP] ; Get the buffer pointer
MOV CS:[DI],AL ; Save the character
INC DI ; Bump pointer and handle wrap
MOV AX,OFFSET i_buf_e
ADD AX,BP
CMP DI,AX
JL nowrap
MOV DI,OFFSET i_buf
ADD DI,BP
nowrap:
cmp i_count[BP],buffer_full
jb hand_done
mov DX,CX
add DX,mcr_8250
in al,DX
and AL,11111100B ; Drop DTR & RTS
out DX,AL
mov ah,flags[BP]
or AH,1 ; Remember RTS is off
mov flags[BP],AH
hand_done:
CMP DI,i_buf_out[BP] ; Overflow of buffer?
JNE noover
OR last_rs[BP],2 ; Overrun indicate
JMP SHORT serint_8250_exit ; Don't save the updated pointer
noover:
MOV i_buf_in[BP],DI ; Save the updated pointer
inc i_count[BP] ; inc char count
serint_8250_exit:
MOV AL,20H ; Tell 8259 we are done
OUT pic_cmd_port,AL
POP DI ; Restore registers
POP CX
POP AX
POP DX
POP BP
IRET ; Exit
program_end:
; Main line to initialize.
ASSUME DS: everything
; Constants only needed by initialization
P3F8 DB 0 ;1 IF CARD AT 3F8
P2F8 DB 0 ;1 IF CARD AT 2F8
HELLO DB CR,LF
DB 'COM1BIOS Driver v1.5',CR,LF
DB 'Dec 18, 1986 '
DB CR,LF,'$'
BYE DB CR,LF
DB 'Driver Installed OK!'
DB CR,LF,'$'
LOADED DB CR,LF
DB 'COM1BIOS already loaded!'
DB CR,LF,'$'
COM1F DB CR,LF
DB 'COM1: board found at 03F8',CR,LF
DB '$'
COM2F DB CR,LF
DB 'COM2: board found at 02F8',CR,LF
DB '$'
NOCOM DB CR,LF
DB 'COM1: board not found.'
DB CR,LF
DB 'Driver NOT installed!',CR,LF
DB '$'
; INITIALIZE ROUTINE
start: MOV AX,CS ; Point DS in the right place
MOV DS,AX
CALL SINON ;PRINT SIGN ON
MOV DX,00 ;Check to see if support already loaded
MOV AH,04
INT 14H
CMP AX,0AA55H
JZ EXIT ;Must be loaded
CALL CNFIG ;CHECK CONFIGURATION
OR AX,AX
JNZ EREXIT ;JMP IF ERRORS
CALL init_vectors ;SET INTERRUPT VECTORS
CALL SINOFF ;PRINT SIGN OFF
MOV AL,0 ;set exit code
MOV DX,OFFSET program_end
MOV CL,4
SHR DX,CL
INC DX
MOV AH,31H
INT 21H ; Terminate but stay resident
EREXIT: MOV AL,1 ;set exit code = Error
MOV AH,4CH
INT 21H ; Terminate and return
EXIT: LEA DX,LOADED
MOV AH,9
INT 21H
MOV AL,0 ;set exit code = Ok
MOV AH,4CH
INT 21H ; Terminate and return
;---------
CNFIG: CALL FNDPT ;Find Ports
CMP P3F8,1
JNE CNF1
LEA DX,COM1F ;Say COM1 Found
MOV AH,9
INT 21H
CNF1: CMP P2F8,1
JNE CNF2
LEA DX,COM2F ;Say COM2 Found
MOV AH,9
INT 21H
CNF2: CMP P3F8,1
JE CNF3
LEA DX,NOCOM ;Say OOPS
MOV AH,9
INT 21H
CNFERR: MOV AX,0FFFFH ;Set Error
RET
CNF3: SUB AX,AX
RET
;------------
FNDPT: MOV DX,03F8H
CALL CKPORT
CMP BP,0
JZ PT2
INC P3F8
PT2: MOV DX,02F8H
CALL CKPORT
CMP BP,0
JZ PT3
INC P2F8
PT3: RET
; Check for valid Port
; Enter with DX containing Port address
; Exit with BP=Port address if port found BP=0 if not found
CKPORT: MOV BP,DX ;For return
MOV CL,DL ;Keep DL Handy
ADD DX,3
IN AL,DX ;Save old LCR in CH
MOV CH,AL
MOV AL,80H ;Address Divisor Latch
OUT DX,AL
CALL WAIT
MOV DL,CL
IN AL,DX
MOV AH,AL ;Save old Divisor
CALL WAIT
INC DX
IN AL,DX ;Save old Divisor
MOV BX,AX
CALL WAIT
MOV DL,CL
MOV AL,55H ;OUTPUT 55
OUT DX,AL
CALL WAIT
INC DX
MOV AL,0AAH
OUT DX,AL ;OUTPUT AA
CALL WAIT
MOV DL,CL
IN AL,DX ;Read New Divisor
MOV AH,AL
CALL WAIT
INC DX
IN AL,DX
CMP AX,55AAH ;DO THEY MATCH?
JZ Match
XOR BP,BP ;Zero - no match
Match: MOV DL,CL
MOV AL,BH ;Restore old Divisor
OUT DX,AL
CALL WAIT
INC DX
MOV AL,BL
OUT DX,AL
CALL WAIT
INC DX
INC DX ;and old LCR
MOV AL,CH
OUT DX,AL
CALL WAIT
WAIT: RET
;---------
;PRINT SIGNON
SINON: LEA DX,HELLO
MOV AH,9
INT 21H
RET
;PRINT SIGNOFF
SINOFF: LEA DX,BYE
MOV AH,9
INT 21H
RET
; Now snatch the BIOS comm vector (Int 14)
init_vectors:
MOV AL,14H
MOV AH,35H
INT 21H
MOV old_bios_vector,BX ; save old vector
MOV old_bios_vector+2,ES
MOV DX,OFFSET rsint ; Replace with our vector
MOV AL,14H
MOV AH,25H
INT 21H
; Set the hardware interrupt vector
XOR bp,bp ; Get a zero
MOV DX,OFFSET serint_8250 ; Get our address
MOV AL,hiv[BP]
MOV AH,25H
INT 21H
; Initialize the buffer ring pointers
MOV AX,OFFSET i_buf ; Get start of buffer address
ADD AX,BP ; include our offset
MOV i_buf_in[BP],AX ; Put in the buffer pointers
MOV i_buf_out[BP],AX ; Put in the buffer pointers
; Set the interrupt registers in the UART and clean things up
CLI ; Disable interrupts
IN AL,pic_mask_port ; Set up 8259 interupt controller
AND AL,int_mask[BP] ; Enable the interrupts for this device
OUT pic_mask_port,AL
MOV CX,baseaddr[BP] ; Get base address for chip
MOV DX,CX ; Compute port address for the IER
ADD DX,ier_8250
MOV AL,1 ; Enable data interrupt only
OUT DX,AL
MOV DX,CX ; Compute port address for the RBR
ADD DX,rbr_8250
IN AL,DX ; Read the input buffer and throw it away
; Enable interrupts
STI ; Enable CPU to receive interupts
RET
everything ENDS
END foo